package org.bopis.services.db;

import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Calendar;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bopis.utilidades.Utilidades;

import com.boole.model.Usuario;

/**
 * Clase que realiza los accesos de base de datos para el acceso al sistema, olvido de contraseña, etc.
 * @author i.fernandezmolina
 *
 */
public class DAOUsuario extends DAOBase{
	
	private static Log log = LogFactory.getLog(DAOUsuario.class);
	private static SQLSentences sqlSentences = SQLSentences.getInstance();

	/**
	 * Metodo usado para hacer login en el sistema. Busca a un usuario a través del email y la password
	 * @param email cadena con el email
	 * @param password cadena con la password
	 * @return objeto Usuario con los datos del mismo, null en caso contrario
	 */
	public static Usuario authenticate(String email, String password){
  		
  		//String query = "SELECT SCREENNAME, NOMBRE, APELLIDO1, APELLIDO2, EMPRESA, CONTACTO, TELEFONO, EMAIL, PWD, FECHA_ALTA, FECHA_BAJA, ACTIVO, CODIGO_ACTIVACION FROM USUARIO WHERE EMAIL = ? AND PWD = ? AND ACTIVO = true";
		String query = sqlSentences.getProperty("sql.authenticate", "");
  		Connection con = getConnection();
  		PreparedStatement ps =null;
  		ResultSet result = null;
		Usuario usuario = null;
  		
	    try {
	    
	    	ps = con.prepareStatement(query);
	    	
      		// Pasamos los parómetros a la query.
      		ps.setString(1, email);
      		ps.setString(2, password);
      		
      		// Ejecutamos la query y obtenemos el resultado.
      		result = ps.executeQuery();
      		
      		if (result.next()){
      			
      			int i = 1;
      			
		      	usuario = new Usuario();		      	
		      	usuario.setScreenname(result.getString(i++));
		      	usuario.setNombre(result.getString(i++));
		      	usuario.setApellido1(result.getString(i++));
		      	usuario.setApellido2(result.getString(i++));
		      	usuario.setEmpresa(result.getString(i++));
		      	usuario.setContacto(result.getString(i++));
		      	usuario.setTelefono(result.getString(i++));
		      	usuario.setEmail(result.getString(i++));
		      	usuario.setPwd(result.getString(i++));
		      	usuario.setFechaAlta(result.getDate(i++));
		      	usuario.setFechaBaja(result.getDate(i++));
		      	usuario.setActivo(result.getBoolean(i++));
		      	usuario.setCodigoActivacion(result.getString(i++));
			}
        }
		catch (SQLException se){
			log.error("Se ha producido un error de BD.");  
			log.error(se.getMessage());
            se.printStackTrace();
		}finally{
			try{
				if(result != null)
					result.close();
				if(ps != null)
					ps.close();
				if(con != null)
					con.close();
			}catch(Exception e){
				log.error("Error cerrando conexiones");
			}			
		}
  	
  		return usuario;
    }
  	
	/**
	 * Metodo que obtiene los datos de un usuario a través de su email
	 * @param email cadena con el email del usuario
	 * @return objeto Usuario con los datos del usuario, null si no lo encontró
	 */
  	public static Usuario getUsuarioByEmail(String email){
  		
  		//String query = "SELECT SCREENNAME, NOMBRE, APELLIDO1, APELLIDO2, EMPRESA, CONTACTO, TELEFONO, EMAIL, PWD, FECHA_ALTA, FECHA_BAJA, ACTIVO, CODIGO_ACTIVACION FROM USUARIO WHERE EMAIL = ?";
  		String query = sqlSentences.getProperty("sql.get.usuario.by.email","");
  		Connection con = getConnection();
  		PreparedStatement ps =null;
  		ResultSet result = null;
		Usuario usuario = null;
  		
	    try {
	    
	    	ps = con.prepareStatement(query);
      		
      		// Pasamos los parómetros a la query.
      		ps.setString(1, email);
      		
      		// Ejecutamos la query y obtenemos el resultado.
      		result = ps.executeQuery();
      		
      		if (result.next()){
      			
      			int i = 1;
      			
		      	usuario = new Usuario();		      	
		      	usuario.setScreenname(result.getString(i++));
		      	usuario.setNombre(result.getString(i++));
		      	usuario.setApellido1(result.getString(i++));
		      	usuario.setApellido2(result.getString(i++));
		      	usuario.setEmpresa(result.getString(i++));
		      	usuario.setContacto(result.getString(i++));
		      	usuario.setTelefono(result.getString(i++));
		      	usuario.setEmail(result.getString(i++));
		      	usuario.setPwd(result.getString(i++));
		      	usuario.setFechaAlta(result.getDate(i++));
		      	usuario.setFechaBaja(result.getDate(i++));
		      	usuario.setActivo(result.getBoolean(i++));
		      	usuario.setCodigoActivacion(result.getString(i++));
			}
        }
		catch (SQLException se)
		{
			log.error("Se ha producido un error de BD.");  
			log.error(se.getMessage());  
		}finally{
			try{
				if(result != null)
					result.close();
				if(ps != null)
					ps.close();
				if(con != null)
					con.close();
			}catch(Exception e){
				log.error("Error cerrando conexiones");
			}	
		}
  	
  		return usuario;
    }


  	/**
  	 * Metodo que actualiza los datos personales de un usuario
  	 * @param usuario objeto Usuario
  	 * @param emailSession cadena con el email de usuario contenido en sesión hasta el momento
  	 * @return true si todo fue bien, false en caso contrario
  	 */
	public static boolean updateUsuario(Usuario usuario, String emailSession) {
		
		String query = sqlSentences.getProperty("sql.update.usuario", "");
		Connection con = getConnection();
  		PreparedStatement ps =null;
  		boolean exito = true;
  		int i = 1;
		  		
	    try {
	    	
	    	ps = con.prepareStatement(query);
      		
      		ps.setString(i++, usuario.getScreenname());
      		ps.setString(i++, usuario.getNombre());
      		ps.setString(i++, usuario.getApellido1());
      		ps.setString(i++, usuario.getApellido2());
      		ps.setString(i++, usuario.getEmpresa());
      		ps.setString(i++, usuario.getContacto());
      		ps.setString(i++, usuario.getTelefono());
      		ps.setString(i++, usuario.getEmail());
      		ps.setString(i++, emailSession);      		
      		ps.execute();
      		
        }catch (Exception se){
        	log.error("Se ha producido un error de BD.");  
        	log.error(se.getMessage()); 
            se.printStackTrace();
            exito = false;
		}finally{
			try{
				if(ps != null)
					ps.close();
				if(con != null)
					con.close();
			}catch(Exception e){
				log.error("Error cerrando conexiones");
			}	
		}
  	
  		return exito;
	}


	/**
	 * Metodo que obtiene los datos de un usuario a través de su screenName
	 * @param screenName cadena con el screenName del usuario
	 * @return objeto Usuario con los datos del usuario, null si no lo encontró
	 */
	public static Usuario getUsuarioByScreenName(String screenName) {
		
		//String query = "SELECT SCREENNAME, NOMBRE, APELLIDO1, APELLIDO2, EMPRESA, CONTACTO, TELEFONO, EMAIL, PWD, FECHA_ALTA, FECHA_BAJA, ACTIVO, CODIGO_ACTIVACION FROM USUARIO WHERE SCREENNAME = ?";
		String query = sqlSentences.getProperty("sql.get.usuario.by.screenname", "");
  		Connection con = getConnection();
  		PreparedStatement ps =null;
  		ResultSet result = null;
		Usuario usuario = null;
  		
	    try {
	    
	    	ps = con.prepareStatement(query);
      		
      		// Pasamos los parómetros a la query.
      		ps.setString(1, screenName);
      		
      		// Ejecutamos la query y obtenemos el resultado.
      		result = ps.executeQuery();  
      		
      		if (result.next()){
      			
      			int i = 1;
      			
		      	usuario = new Usuario();		      	
		      	usuario.setScreenname(result.getString(i++));
		      	usuario.setNombre(result.getString(i++));
		      	usuario.setApellido1(result.getString(i++));
		      	usuario.setApellido2(result.getString(i++));
		      	usuario.setEmpresa(result.getString(i++));
		      	usuario.setContacto(result.getString(i++));
		      	usuario.setTelefono(result.getString(i++));
		      	usuario.setEmail(result.getString(i++));
		      	usuario.setPwd(result.getString(i++));
		      	usuario.setFechaAlta(result.getDate(i++));
		      	usuario.setFechaBaja(result.getDate(i++));
		      	usuario.setActivo(result.getBoolean(i++));
		      	usuario.setCodigoActivacion(result.getString(i++));
			}
        }
		catch (SQLException se){
			log.error("Se ha producido un error de BD.");  
			log.error(se.getMessage());  
		}finally{
			try{
				if(result != null)
					result.close();
				if(ps != null)
					ps.close();
				if(con != null)
					con.close();
			}catch(Exception e){
				log.error("Error cerrando conexiones");
			}	
		}
  	
  		return usuario;
	}
	
	
	/**
	 * Metodo que obtiene los datos de un usuario a través de su codigo de activacion
	 * @param codigoActivacion cadena con el codigo de activacion del usuario
	 * @return objeto Usuario con los datos del usuario, null si no lo encontró
	 */
	private static Usuario getUsuarioByCodigoActivacion(String codigoActivacion) {
		
		//String query = "SELECT SCREENNAME, NOMBRE, APELLIDO1, APELLIDO2, EMPRESA, CONTACTO, TELEFONO, EMAIL, PWD, FECHA_ALTA, FECHA_BAJA, ACTIVO, CODIGO_ACTIVACION FROM USUARIO WHERE CODIGO_ACTIVACION = ?";
		String query = sqlSentences.getProperty("sql.get.usuario.by.codigo.activacion", "");
  		Connection con = getConnection();
  		PreparedStatement ps =null;
  		ResultSet result = null;
		Usuario usuario = null;
  		
	    try {
	    
	    	ps = con.prepareStatement(query);
      		
      		// Pasamos los parómetros a la query.
      		ps.setString(1, codigoActivacion);
      		
      		// Ejecutamos la query y obtenemos el resultado.
      		result = ps.executeQuery();  
      		
      		if (result.next()){
      			
      			int i = 1;
      			
		      	usuario = new Usuario();		      	
		      	usuario.setScreenname(result.getString(i++));
		      	usuario.setNombre(result.getString(i++));
		      	usuario.setApellido1(result.getString(i++));
		      	usuario.setApellido2(result.getString(i++));
		      	usuario.setEmpresa(result.getString(i++));
		      	usuario.setContacto(result.getString(i++));
		      	usuario.setTelefono(result.getString(i++));
		      	usuario.setEmail(result.getString(i++));
		      	usuario.setPwd(result.getString(i++));
		      	usuario.setFechaAlta(result.getDate(i++));
		      	usuario.setFechaBaja(result.getDate(i++));
		      	usuario.setActivo(result.getBoolean(i++));
		      	usuario.setCodigoActivacion(result.getString(i++));
			}
        }
		catch (SQLException se){
			log.error("Se ha producido un error de BD.");  
			log.error(se.getMessage());  
		}finally{
			try{
				if(result != null)
					result.close();
				if(ps != null)
					ps.close();
				if(con != null)
					con.close();
			}catch(Exception e){
				log.error("Error cerrando conexiones");
			}	
		}
  	
  		return usuario;
	}


	/**
	 * Metodo que inserta un nuevo registro en la tabla de usuarios
	 * @param usuario objeto Usuario con los datos a insertar
	 * @return true si todo fue bien, false en caso contrario
	 */
	public static boolean insertUsuario(Usuario usuario) {
		
		//String query = "INSERT INTO USUARIO(SCREENNAME, NOMBRE, APELLIDO1, APELLIDO2, EMPRESA, CONTACTO, TELEFONO, EMAIL, PWD, FECHA_ALTA, ACTIVO, CODIGO_ACTIVACION) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)";
  		String query = sqlSentences.getProperty("sql.insert.usuario", "");
		Connection con = getConnection();
  		PreparedStatement ps =null;
  		boolean exito = true;
  		int i = 1;
		  		
	    try {
	    	
	    	ps = con.prepareStatement(query);
      		
      		ps.setString(i++, usuario.getScreenname());
      		ps.setString(i++, usuario.getNombre());
      		ps.setString(i++, usuario.getApellido1());
      		ps.setString(i++, usuario.getApellido2());
      		ps.setString(i++, usuario.getEmpresa());
      		ps.setString(i++, usuario.getContacto());
      		ps.setString(i++, usuario.getTelefono());
      		ps.setString(i++, usuario.getEmail());
      		ps.setString(i++, Utilidades.fromStringToMD5(usuario.getPwd()));
      		ps.setDate(i++, new Date(new java.util.Date().getTime()));
      		ps.setBoolean(i++, false);
      		ps.setString(i++, usuario.getCodigoActivacion());
      		
      		ps.execute();
      		
        }catch (Exception se){
        	log.error("Se ha producido un error de BD.");  
        	log.error(se.getMessage()); 
            se.printStackTrace();
            exito = false;
		}finally{
			try{
				if(ps != null)
					ps.close();
				if(con != null)
					con.close();
			}catch(Exception e){
				log.error("Error cerrando conexiones");
			}	
		}
  	
  		return exito;
	}

	public static Usuario activarUsuario(String codigoActivacion) {
		
		//String query = "UPDATE USUARIO SET ACTIVO = true WHERE CODIGO_ACTIVACION = ?";
		String query = sqlSentences.getProperty("sql.activar.usuario", "");
  		Connection con = getConnection();
  		PreparedStatement ps =null;
  		Usuario usuario = null;
  		int i = 1;
		  		
	    try {
	    
	    	ps = con.prepareStatement(query);
      		
      		//activamos al usuario
      		ps.setString(i++, codigoActivacion);
      		ps.executeUpdate();
      		
      		//obtenemos los datos del usuario
      		usuario = getUsuarioByCodigoActivacion(codigoActivacion);
      		
      		
        }catch (Exception se){
        	log.error("Se ha producido un error de BD.");  
        	log.error(se.getMessage());
            usuario = null;
		}finally{
			try{
				if(ps != null)
					ps.close();
				if(con != null)
					con.close();
			}catch(Exception e){
				log.error("Error cerrando conexiones");
			}	
		}
  			
		
		return usuario;
	}

	/**
	 * Metodo que obtiene un usuario por el codigo de activacion y la password
	 * @param codigoActivacion cadena con el codigo de activacion
	 * @param password cadena con la password del usuario en MD5
	 * @return objeto Usuario con los datos encontrados
	 */
	public static Usuario getUsuarioByCodActivacionAndPass(String codigoActivacion, String password){
		
		String query = sqlSentences.getProperty("sql.get.usuario.by.codigo.activacion.and.password", "");
  		Connection con = getConnection();
  		PreparedStatement ps =null;
  		ResultSet result = null;
		Usuario usuario = null;
		int x = 1;
  		
	    try {
	    
	    	ps = con.prepareStatement(query);
      		
      		// Pasamos los parómetros a la query.
      		ps.setString(x++, codigoActivacion);
      		ps.setString(x++, password);
      		
      		// Ejecutamos la query y obtenemos el resultado.
      		result = ps.executeQuery();  
      		
      		if (result.next()){
      			
      			int i = 1;
      			
		      	usuario = new Usuario();		      	
		      	usuario.setScreenname(result.getString(i++));
		      	usuario.setNombre(result.getString(i++));
		      	usuario.setApellido1(result.getString(i++));
		      	usuario.setApellido2(result.getString(i++));
		      	usuario.setEmpresa(result.getString(i++));
		      	usuario.setContacto(result.getString(i++));
		      	usuario.setTelefono(result.getString(i++));
		      	usuario.setEmail(result.getString(i++));
		      	usuario.setPwd(result.getString(i++));
		      	usuario.setFechaAlta(result.getDate(i++));
		      	usuario.setFechaBaja(result.getDate(i++));
		      	usuario.setActivo(result.getBoolean(i++));
		      	usuario.setCodigoActivacion(result.getString(i++));
			}
        }
		catch (SQLException se){
			log.error("Se ha producido un error de BD.");  
			log.error(se.getMessage());  
		}finally{
			try{
				if(result != null)
					result.close();
				if(ps != null)
					ps.close();
				if(con != null)
					con.close();
			}catch(Exception e){
				log.error("Error cerrando conexiones");
			}	
		}
  	
  		return usuario;
	}

	
	/**
	 * Metodo que resetea el codigo de activacion del usuario
	 * @param email cadena con el email del usuario
	 * @return true si todo fue bien, false en caso contrario
	 */
	public static boolean resetCodigoActivacion(String email) {
		
		String query = sqlSentences.getProperty("sql.reset.codigo.activacion", "");
  		Connection con = getConnection();
  		PreparedStatement ps =null;
  		boolean exito = true;
  		int i = 1;
		  		
	    try {
	    
	    	ps = con.prepareStatement(query);
      		ps.setString(i++, Utilidades.fromStringToMD5(String.valueOf(Calendar.getInstance().getTimeInMillis())));
      		ps.setString(i++, email);
      		ps.executeUpdate();
      		     		
        }catch (Exception se){
        	log.error("Se ha producido un error de BD.");  
        	log.error(se.getMessage());
            exito = false;
		}finally{
			try{
				if(ps != null)
					ps.close();
				if(con != null)
					con.close();
			}catch(Exception e){
				log.error("Error cerrando conexiones");
			}	
		}
		
		return exito;
	}

	
	/**
	 * Metodo que actualiza la password del usuario
	 * @param email cadena con el email del usuario
	 * @param password cadena con la nueva password
	 * @return true si todo fue bien, false en caso contrario
	 */
	public static boolean updatePasswordUsuario(String email, String password) {
		
		String query = sqlSentences.getProperty("sql.update.password", "");
  		Connection con = getConnection();
  		PreparedStatement ps =null;
  		boolean exito = true;
  		int i = 1;
		  		
	    try {
	    
	    	ps = con.prepareStatement(query);
      		ps.setString(i++, Utilidades.fromStringToMD5(password));
      		ps.setString(i++, email);
      		ps.executeUpdate();
      		     		
        }catch (Exception se){
        	log.error("Se ha producido un error de BD.");  
        	log.error(se.getMessage());
            exito = false;
		}finally{
			try{
				if(ps != null)
					ps.close();
				if(con != null)
					con.close();
			}catch(Exception e){
				log.error("Error cerrando conexiones");
			}	
		}
		
		return exito;
	}
	
}